package gr.gsis.cobol;

import gr.gsis.cobol.data.Formatter;
import gr.gsis.cobol.spec.FieldSpec;
import gr.gsis.cobol.spec.RecordSpec;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.PropertyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FileMarshaller {

	private static final Logger LOGGER = LoggerFactory.getLogger(FileMarshaller.class);
	
	private boolean trimming = true;
	
	private final Map<String, Formatter> formatters;
	
	public FileMarshaller(Map<String, Formatter> formatters) {
		this.formatters = formatters;
	}
	
	public void unmarshal(InputStream is, Set<RecordSpec> recordSpecs, RecordHandler recordHandler) 
	throws IOException, Exception {
		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		
		String line;
		while ((line = reader.readLine()) != null) {
			char recordType = line.charAt(0);
			
			RecordSpec spec = null;
			for (RecordSpec each: recordSpecs) {
				if (each.getRecordType() == recordType) {
					spec = each;
				}
			}
			
			if (spec == null) {
				LOGGER.warn("Skipping recordType: {}", recordType);
				continue;
			}
			
			Object recordObject = null;
			if (spec.getClassName() != null) {
				recordObject = Class.forName(spec.getClassName()).getConstructor().newInstance();
			}
			
			int pos = 0;
			for (FieldSpec each: spec.getFieldSpecs()) {
				int length = PictureUtils.getLength(each.getPicture());
				
				if (pos + length > line.length()) {
					LOGGER.warn("Could not read all fields");
					break;
				}
				
				String stringValue = line.substring(pos, pos+length);
				if (trimming) stringValue = stringValue.trim();
				Object value = stringValue;
				
				if (each.getFormatterId() != null) {
					Formatter formatter = formatters.get(each.getFormatterId());
					
					if (formatter != null) {
						value = formatter.toObject(each, stringValue);
					} else {
						LOGGER.warn("Could not find formatter: {}", each.getFormatterId());
					}
				}
				
				if (recordObject != null && each.getPropertyName() != null) {
					PropertyUtils.setProperty(recordObject, each.getPropertyName(), value);
				}
				
				pos += length;
			}

			if (recordHandler != null && recordObject != null) {
				recordHandler.onRecord(recordType, recordObject);
			}
		}
	}
	
}
